<template>
	<div class="cmd-window" :class="'cmd-window-' + classString">
		<!-- <p v-for="(item, index) in stdout" :key="index">{{ item }}</p> -->
		<!-- 虚拟列表 -->
		<DynamicScroller class="scroller" :items="stdout" :min-item-size="30">
			<template v-slot="{ item, index, active }">
				<DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item]" :index="index">
					<div class="desc">{{ item }}</div>
				</DynamicScrollerItem>
			</template>
		</DynamicScroller>
		<div class="auto-input-cmd" v-if="type == 'auto'">
			<el-input :class="classString" :ref="classString" v-model="autoInput" @keyup.enter.native="cmdSub" placeholder="请输入"></el-input>
		</div>
		<button @click="exitRun" v-if="workerProcess">结束任务</button>
		<button @click="exitWindow">关闭窗口</button>
	</div>
</template>

<script>
const exec = require('child_process').exec
const kill = require('tree-kill')
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
export default {
	props: {
		runKey: {
			default: ''
		},
		checkIndex: {
			default: false
		},
		type: {
			default: ''
		},
		path: {
			default: ''
		}
	},
	data() {
		return {
			stdout: [],
			workerProcess: null,
			classString: '',
			autoInput: ''
		}
	},
	components: {
		DynamicScroller,
		DynamicScrollerItem
	},
	watch: {
		checkIndex(newValue) {
			if (newValue) {
				this.scrollToBottom()
			}
		}
	},
	mounted() {
		this.classString = this.randomString(8)
		this.npmRun(this.runKey)
	},
	update() {
		this.scrollToBottom()
	},
	methods: {
		scrollToBottom() {
			this.$nextTick(() => {
				let box = document.getElementsByClassName('cmd-window-' + this.classString)
				if (box[0]) {
					box[0].scrollTop = box[0].scrollHeight
				}
			})
		},
		randomString(len) {
			len = len || 32
			let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' /** **默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
			let maxPos = $chars.length
			let pwd = ''
			for (let i = 0; i < len; i++) {
				pwd += $chars.charAt(Math.floor(Math.random() * maxPos))
			}
			return pwd
		},
		// 自定义窗口
		cmdSub(key) {
			const callback = () => {
				this.$nextTick(() => {
					this.$refs[this.classString].focus()
				})
			}
			const inputValue = this.autoInput
			this.stdout.push(inputValue)
			this.runExec(inputValue, this.path, callback)
			this.autoInput = ''
		},
		//
		npmRun(key) {
			// 自定义窗口开启
			if (this.type == 'auto') {
				this.$nextTick(() => {
					this.$refs[this.classString].focus()
				})
				return
			}
			this.runExec(key, this.path)
		},
		runExec(cmdStr, cmdPath, callback) {
			const iconv = require('iconv-lite')
			const encoding = 'cp936'
			const binaryEncoding = 'binary'
			const that = this
			const filterConsole = data => {
				return iconv.decode(new Buffer(data, binaryEncoding), encoding)
			}
			this.workerProcess = exec(cmdStr, { cwd: cmdPath, maxBuffer: 1234567890, encoding: binaryEncoding })
			// 打印正常的后台可执行程序输出
			this.workerProcess.stdout.on('data', function(data) {
				// that.stdout.push(filterConsole(data))
				that.stdout.push(data)
				that.scrollToBottom()
			})
			// 打印错误的后台可执行程序输出
			this.workerProcess.stderr.on('data', function(data) {
				// that.stdout.push(filterConsole(data))
				that.stdout.push(data)
				that.scrollToBottom()
			})
			// // 退出之后的输出
			this.workerProcess.on('close', function(code) {
				that.stdout.push('任务结束,返回状态码为' + code)
				that.scrollToBottom()
			})
			// // 失败之后的输出
			this.workerProcess.on('error', function(code) {
				that.stdout.push('操作失败' + code)
				that.scrollToBottom()
			})
			// // 退出之后的输出
			this.workerProcess.on('exit', function(code, signal) {
				that.stdout.push('exit,状态码为' + code)
				that.scrollToBottom()
				if (callback) {
					callback()
				}
			})
		},
		// 结束进程树
		exitRun() {
			if (!this.workerProcess) {
				return
			}
			kill(this.workerProcess.pid, 'SIGKILL', function(err) {})
		},
		back() {
			return new Promise((res, rej) => {
				if (!this.workerProcess) {
					res('已经关闭')
				}
				kill(this.workerProcess.pid, 'SIGKILL', function(err) {
					res('关闭成功')
				})
			})
		},
		exitWindow() {
			const that = this
			if (this.type == 'auto') {
				// this.autoInput = ''
			}
			if (!this.workerProcess) {
				that.$emit('exitWindow', that.runKey)
				return
			}
			kill(this.workerProcess.pid, 'SIGKILL', function(err) {
				that.$emit('exitWindow', that.runKey)
			})
		},
		// 根据pid匹配系统进程并结束
		viewProcessMessage(pid, cb) {
			let cmd = process.platform === 'win32' ? 'tasklist' : 'ps aux'
			exec(cmd, function(err, stdout, stderr) {
				if (err) {
					return console.error(err)
				}
				stdout.split('\n').filter(line => {
					let processMessage = line.trim().split(/\s+/)
					let processName = processMessage[1] // processMessage[0]进程名称 ， processMessage[1]进程id
					if (processName == pid) {
						return cb(processMessage[1])
					}
				})
			})
		}
	}
}
</script>

<style scoped lang="scss">
/deep/ .el-input__inner {
	background-color: #000000;
	border: none;
	color: white;
}
.scroller {
  height: 100%;
}
.desc {
  text-align: left;
}
.cmd-window {
	// width: 567px;
	color: #ffffff;
	background-color: #000000;
	max-height: 300px;
	overflow: auto;
	word-wrap: break-word;
	word-break: break-all;
	white-space: pre-wrap;
	padding: 10px;
	p {
		margin-bottom: 5px;
		text-align: left;
	}
	.scroller {
		height: 100%;
	}
}
</style>
